#include "string.h"
#include "stdlib.h"
#include "stdio.h"
#include "inc/core/task1d.h"

#define ESOURCE 1
#define BSOURCE 2

void make_in_bounds(particles_set* set, int num, floatdig min, floatdig max)
{
    floatdig sL = max - min;
    floatdig* z_pos  = &(set->particles[num].pos.v[Z]);
    int k = 0;
    while (*z_pos < min)
    {
        *z_pos += sL;
        //for (k = VX; k <= VY; k++)
        //{
         //   particle_set_particle_speed_maxwellian(set, num, k, SIGMA);
        //}
    }
    while (*z_pos > max)
    {
        *z_pos -= sL;
        {
            //particle_set_particle_speed_maxwellian(set, num, k, SIGMA);
        }
    }
}

//void do_add_source(task1d* task, void* source, int type) {
//    if ((task != NULL) && (source != NULL)) {
//        void** new_sources;
//        void* sources;
//        int* num_of_sources;
//        int type_size = 0;
//        switch (type) {
//            case ESOURCE:
//                sources = (void*) (task->sources.esources);
//                num_of_sources = &(task->sources.num_of_esources);
//                type_size = sizeof (esource);
//                break;
//            case BSOURCE:
//                sources = (void*) (task->sources.bsources);
//                num_of_sources = &(task->sources.num_of_bsources);
//                type_size = sizeof (bsource);
//                break;
//        }
//        if ((sources == NULL) || (*num_of_sources == 0)) {
//            new_sources = malloc(type_size);
//            *num_of_sources = 1;
//            new_sources[0] = source;
//        } else {
//            int i = 0;
//            new_sources = (void*) malloc((type_size)*(*num_of_sources + 1));
//            void* new_sources_mover = new_sources;
//            void* sources_mover = sources;
//            for (i = 0; i < *num_of_sources; i++) {
//                memcpy(new_sources_mover, sources_mover, type_size);
//                new_sources_mover += type_size;
//                sources_mover += type_size;
//
//            }
//            free(sources);
//            new_sources_mover += type_size;
//            memcpy(new_sources_mover, source, type_size);
//            sources = new_sources;
//            *num_of_sources++;
//        }
//        switch (type) {
//            case ESOURCE:
//                task->sources.esources = new_sources;
//                break;
//
//            case BSOURCE:
//                task->sources.bsources = new_sources;
//                break;
//        }
//    }
//
//}

void task1d_add_esource(task1d* task, esource source) {
#ifdef VERBOSE
    printf("add new esource in the task\n");
#endif
    //do_add_source(task, source, ESOURCE);
	task->sources.esources = (esource*)malloc(sizeof(esource));
	task->sources.esources[0] = source;
	task->sources.num_of_esources = 1;

}

void task1d_add_bsource(task1d* task, bsource source) {
#ifdef VERBOSE
    printf("add new bsource in the task\n");
#endif
    //do_add_source(task, source, BSOURCE);
	task->sources.bsources = (bsource*)malloc(sizeof(bsource));
	task->sources.bsources[0] = source;
	task->sources.num_of_bsources = 1;
}

void task1d_set_add_pgd(task1d* task, pgm_set* pgd_set) {
#ifdef VERBOSE
    printf("add new pgd int task\n");
#endif
    if ((task->pgm == NULL) || (task->num_of_species == 0)) {
        free(task->pgm);
        task->pgm = (pgm_set*) malloc(sizeof (pgm_set));
        memcpy(&(task->pgm[0]), pgd_set, sizeof (pgm_set));
        task->num_of_species = 1;
    } else {
        pgm_set* new_pgm_set = (pgm_set*) malloc(sizeof (pgm_set)*(task->num_of_species + 1));
        int i;
        for (i = 0; i < task->num_of_species; i++) {
            memcpy(&(new_pgm_set[i]), &(task->pgm[i]), sizeof (pgm_set));
        }
        memcpy(&(new_pgm_set[task->num_of_species]), pgd_set, sizeof (pgm_set));
        free(task->pgm);
        task->pgm = new_pgm_set;
        task->num_of_species++;
    }
}

void task1d_set_boundaries(task1d* task, boundary_conditions_uc1d* bonds) {
#ifdef VERBOSE
    printf("set boundary conditions for the task\n");
#endif
    memcpy(&(task->bonds), bonds, sizeof task->bonds);
}

void task1d_clear_task(task1d* task) {
#ifdef VERBOSE
    printf("clear all data from the task\n");
#endif
    free(task->pgm);
    free(task->sources.esources);
    free(task->sources.bsources);
}

void task1d_start_evaluations(task1d* task) {
    int num_of_species = task->num_of_species;
    int i = 0;
    #ifdef DEBUG
    int k = 0;
    int j = 0;
    #endif

    task1d_postprocessing(task);
    while (task->current_timevar < task->end_timevar) {
        for (i = 0; i < num_of_species; i++) {
            #ifdef DEBUG
            char filename[FILENAME_MAX];
            #endif
            pgm_set* pgm = &(task->pgm[i]);
            mover1d_single_iteration(pgm->mover, pgm->grid, pgm->set);
            #ifdef DEBUG
            //sprintf(filename, "/home/oddi/Code/edistr/test/phi_%d.dat", k);
            //ucgrid1d_print_phi_into_file_debug(filename, pgm->grid);
            //sprintf(filename, "/home/oddi/Code/edistr/test/rho_%d.dat", k);
            //ucgrid1d_print_rho_into_file_debug(filename, pgm->grid);
            //if (k == 1)
            //{
                //sprintf(filename, "p_pos_%d.dat", j);
                //particle_dump_particles_pos_into_file(pgm->set, HOMEDIR, filename, L/2 + DL, 2*CELLSIZE);
                //sprintf(filename, "p_speed_%d.dat", j);
                //particle_dump_particles_speed_into_file(pgm->set, HOMEDIR, filename, L/2 + DL, 2*CELLSIZE);
                //sprintf(filename, "tre_dump_%d.dat", j);
                //particle_dump_trenergy_into_file(pgm->set, HOMEDIR, filename, L/2 + DL, 2*CELLSIZE, NVTRSTEPS);
                sprintf(filename, "staten_%d.dat", j);
                ucgrid1d_put_estatic_energy_into_file(HOMEDIR, filename, pgm->grid);

                //sprintf(filename, "/home/oddi/Code/edistr/test/rho_%d.dat", j);
                //ucgrid1d_print_rho_into_file_debug(filename, pgm->grid);
                //sprintf(filename, "/home/oddi/Code/edistr/test/E_ext_%d.dat", j);
                //mover1d_make_snapshot_of_ext_E(pgm->grid, pgm->mover, filename);
                //sprintf(filename, "/home/oddi/Code/edistr/test/phi_%d.dat", j);
                //ucgrid1d_print_phi_into_file_debug(filename, pgm->grid);
                j++;
                //k = 0;
            //}
            //k++;
            #endif
        }
        task1d_postprocessing(task);
        task->current_timevar += task->dt;
    }


}

void task1d_postprocessing(task1d* task) {
    int num_of_species = task->num_of_species;
    int i = 0;
    int k = 0;
    floatdig min_z = task->bonds.min_z;
    floatdig max_z = task->bonds.max_z;
    for (i = 0; i < num_of_species; i++) {
        pgm_set* pgm = &(task->pgm[i]);
        particles_set* set = pgm[i].set;
        int j;
        for (j = 0; j < set->num_of_particles; j++) {
            if (set->particles[j].active == PARTICLE_ACTIVE)
            {
                make_in_bounds(set, j, task->bonds.min_z, task->bonds.max_z);   
            }
            
        }
    }

}

